package com.gzhryc.shared_device.oem.micro.queue.work;

import com.gzhryc.common.DateTools;
import com.gzhryc.common.NumberTools;
import com.gzhryc.common.exceptions.LogicException;
import com.gzhryc.common.json.JsonTools;
import com.gzhryc.common.kafka.JFKafkaProducer;
import com.gzhryc.common.kafka.KafkaProducerFactory;
import com.gzhryc.common.kafka.models.KafkaMessage;
import com.gzhryc.common.logging.Logger;
import com.gzhryc.jdbc.JdbcSession;
import com.gzhryc.shared_device.base.enums.ELogState;
import com.gzhryc.shared_device.base.models.OperateInfo;
import com.gzhryc.shared_device.cdcz.code.dao.db.CDCZOrder;
import com.gzhryc.shared_device.cdcz.code.dao.enums.CDCZOrderEnum;
import com.gzhryc.shared_device.cdcz.code.services.CDCZOrderChargeLogService;
import com.gzhryc.shared_device.cdcz.code.services.CDCZOrderService;
import com.gzhryc.shared_device.cdcz.core.ICDCZNetworkService;
import com.gzhryc.shared_device.cdcz.core.models.CDCZExecuteResult;
import com.gzhryc.shared_device.oem.code.HttpNetworkServiceUtils;
import com.gzhryc.shared_device.oem.code.KafkaEventConstants;
import com.gzhryc.shared_device.oem.code.business.EBusinessType;
import com.gzhryc.shared_device.oem.code.member.services.MemberBusinessOrderService;
import com.gzhryc.shared_device.oem.code.member.services.MemberWalletService;
import com.gzhryc.shared_device.oem.code.order.RedisCacheManager;
import com.gzhryc.shared_device.oem.code.order.event.OrderFinishEvent;
import com.gzhryc.shared_device.oem.code.place.services.PlaceBusinessConfigService;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.apache.commons.lang3.time.DateUtils;

import java.sql.SQLException;
import java.util.Date;
import java.util.List;

/**
 * 充电插座收费检查
 */
public class CDCZCacheFeeCheckRunnable implements Runnable{

    static Logger log = Logger.getLogger(CDCZCacheFeeCheckRunnable.class);

    OperateInfo operateInfo;

    public CDCZCacheFeeCheckRunnable(OperateInfo operateInfo){
        this.operateInfo = operateInfo;
    }

    @Override
    public void run() {
        try {
            List<CDCZOrder> deviceOrderList = RedisCacheManager.findWorkingCDCZDeviceOrder();
            if (deviceOrderList != null && deviceOrderList.size() > 0) {
                for (CDCZOrder deviceOrder : deviceOrderList) {
                    int times = 10;     //10分钟扣费一次
                    Date currentDate = new Date();
                    Long minute = DateTools.differenceMinute(deviceOrder.getStartDate(), currentDate);
                    if (minute > times) {
                        Date lastDeductionDate = deviceOrder.getStartDate();
                        boolean flag = deviceOrder.getMaxUsePower() != null;
                        if (flag) {
                            if (deviceOrder.getLastDeductionDate() != null) {
                                lastDeductionDate = deviceOrder.getLastDeductionDate();
                                minute = DateTools.differenceMinute(deviceOrder.getLastDeductionDate(), new Date());
                                if (minute < times) {
                                    log.info("最后结算时间低于10分钟，不进行计算，订单号：{{0}}，最后结算时间：{{1}}", deviceOrder.getTradeNo()
                                            , DateFormatUtils.format(deviceOrder.getLastDeductionDate(), "yyyy-MM-dd HH:mm:ss"));
                                    flag = false;
                                }
                            }
                        } else {
                            log.info("未获取最大使用功率，不进行计算，订单号：{{0}}", deviceOrder.getTradeNo());
                        }

                        if (flag) {
                            Long payMoney = PlaceBusinessConfigService.self().getCDCZPayMoney(deviceOrder.getPlaceId(), deviceOrder.getMaxUsePower());
                            if (payMoney == null) {
                                log.error("未找到功率区间收费标准，订单号：{{0}}", deviceOrder.getTradeNo());
                                break;
                            }
                            Long count = minute / times;
                            Long walletMoney = NumberTools.multiply(NumberTools.divide(payMoney, 4, 0), count);
                            lastDeductionDate = DateUtils.addMinutes(lastDeductionDate, count.intValue() * times);       //获取最后计费时间，10的倍数
                            Integer operateState = ELogState.Fail.index();
                            String errorMsg = "定时收费，每15分钟扣费失败";

                            JdbcSession.begin();
                            try {
                                if (CDCZOrderService.self(deviceOrder.getCreateDate()).addUseMoney(deviceOrder, payMoney, walletMoney, lastDeductionDate)) {
                                    operateInfo.setOperateNote(deviceOrder.getTradeNo() + "订单每15分钟扣费");
                                    if (MemberWalletService.self().reduceMoney(deviceOrder.getMemberId(), walletMoney, operateInfo)) {
                                        //同步会员订单
                                        MemberBusinessOrderService.self(deviceOrder.getCreateDate()).addUseMoney(deviceOrder.getTradeNo(), walletMoney);
                                        JdbcSession.commit();
                                        operateState = ELogState.Success.index();
                                        errorMsg = null;
                                    }
                                } else {
                                    errorMsg = "定时收费，每10分钟扣费，修改设备订单失败";
                                }
                            } catch (SQLException e) {
                                log.error(e.getMessage(), e);
                                errorMsg = e.getMessage();
                            } catch (LogicException e) {
                                log.error(e.getMessage(), e);
                                errorMsg = e.getMessage();
                            } finally {
                                JdbcSession.end();
                            }

                            //添加订单日志
                            operateInfo.setOperateNote("定时收费，每10分钟扣费" + NumberTools.getMoneyLiStr(walletMoney) + "元，当前功率：" + deviceOrder.getMaxUsePower()
                                    + "，每小时收费：" + NumberTools.getMoneyLiStr(payMoney) + "元");
                            CDCZOrderChargeLogService.self(deviceOrder.getCreateDate()).add(deviceOrder, operateInfo, operateState, errorMsg);

                            if (ELogState.Fail.index().equals(operateState)) {
                                deviceOrder = CDCZOrderService.self(deviceOrder.getCreateDate()).getByTradeNo(deviceOrder.getTradeNo());
                                if (!CDCZOrderEnum.State.Finish.index().equals(deviceOrder.getState())) {
                                    ICDCZNetworkService networkService = HttpNetworkServiceUtils.getCDCZNetworkService(deviceOrder.getIotId());
                                    CDCZExecuteResult executeResult = networkService.closeCharge(deviceOrder.getChargeSocketSn(), deviceOrder.getSlotNum());
                                    log.info("充电插座定时每15分钟扣费失败，关闭充电返回：{{0:json}}", executeResult);
                                }
                                //清理缓存，避免定时器重复处理
                                RedisCacheManager.removeWorkingCDCZDeviceOrder(deviceOrder.getTradeNo());
                            } else {
                                //按当前功率检查钱包金额
                                if (!MemberWalletService.self().hasMoney(deviceOrder.getMemberId(), walletMoney)) {
                                    try {
                                        //清理缓存，避免定时器重复处理
                                        RedisCacheManager.removeWorkingCDCZDeviceOrder(deviceOrder.getTradeNo());

                                        ICDCZNetworkService networkService = HttpNetworkServiceUtils.getCDCZNetworkService(deviceOrder.getIotId());
                                        operateInfo.setOperateNote("强制停,钱包金额不足以支付下一次收费");
                                        if (CDCZOrderService.self(deviceOrder.getCreateDate()).noMoneyToFinish(deviceOrder, networkService, operateInfo)) {
                                            deviceOrder = CDCZOrderService.self(deviceOrder.getCreateDate()).getByTradeNo(deviceOrder.getTradeNo());
                                            MemberBusinessOrderService.self(deviceOrder.getCreateDate()).finish(deviceOrder.getTradeNo(), deviceOrder.getMoney(),
                                                    deviceOrder.getPayMoney(), deviceOrder.getWalletMoney(),operateInfo);
                                            JFKafkaProducer producer = KafkaProducerFactory.self().getProducer();
                                            if (producer != null) {
                                                OrderFinishEvent event = new OrderFinishEvent(EBusinessType.CDCZ.index(), deviceOrder.getTradeNo(), deviceOrder.getCreateDate(), operateInfo);
                                                KafkaMessage kafkaMessage = new KafkaMessage(KafkaEventConstants.TOPIC_Order, KafkaEventConstants.KEY_OrderFinish, JsonTools.toJson(event));
                                                producer.send(kafkaMessage);
                                            }
                                        } else {
                                            log.error("完成充电插座订单失败，订单信息：{{0:json}}", deviceOrder);
                                        }
                                    } catch (Exception e) {
                                        log.error(e.getMessage(), e);
                                    }
                                } else {
                                    //更新缓存，主要是更新最后收费时间
                                    deviceOrder.setLastDeductionDate(lastDeductionDate);
                                    deviceOrder.setMoney(deviceOrder.getMoney() + walletMoney);
                                    deviceOrder.setMaxPayMoney(payMoney);
                                    deviceOrder.setWalletMoney(deviceOrder.getWalletMoney() + walletMoney);
                                    RedisCacheManager.saveWorkingCDCZDeviceOrder(deviceOrder);
                                }
                            }
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }
}
